package cn.tedu.toa.management.shiro.realm;

import cn.tedu.toa.management.sys.entity.SysUsers;
import cn.tedu.toa.management.sys.mapper.SysMenusMapper;
import cn.tedu.toa.management.sys.mapper.SysRolesMapper;
import cn.tedu.toa.management.sys.mapper.SysUsersMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

public class LoginRealm extends AuthorizingRealm {

    @Autowired
    private SysUsersMapper sysUsersMapper;
    @Autowired
    private SysRolesMapper rolesMapper;
    @Autowired
    private SysMenusMapper menusMapper;

    /**
     * 用于将当前用户的权限封装到 AuthorizationInfo 接口的某个实现类的对象中
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1.先获取当前用户信息(用户id)
        SysUsers user= (SysUsers) principalCollection.getPrimaryPrincipal();
        Integer userId=user.getId();
        //2.根据用户id查询对应的角色(集合)
        List<Integer> roleIds=sysUsersMapper.selectRoleIdsByUserId(userId);
        if(roleIds==null || roleIds.size()<1){
           throw new AuthorizationException();
        }
        //3.根据角色查询对应的菜单的ids
        Integer[] roleIdsArr=new Integer[roleIds.size()];
        List<Integer> menuIds=rolesMapper.selectMenuIdsByRoleIds(roleIds.toArray(roleIdsArr));
        if(menuIds==null || menuIds.size()<1){
            throw new AuthorizationException();
        }
        //4.根据菜单ids查询对应的权限
        Integer[] menuIdsArr=new Integer[menuIds.size()];
        Set<String> permissions= menusMapper.selectPermissionsByMenuIds(menuIds.toArray(menuIdsArr));
        //5.将查询到的权限封装到shiro框架的某对象中
        SimpleAuthorizationInfo info= new SimpleAuthorizationInfo();
        info.setStringPermissions(permissions);
        return info;
    }

    /**
     * 用户封装正确的用户信息
     * AuthenticationInfo 身份认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取前端的用户信息  用户名  和密码
        UsernamePasswordToken uptoken= (UsernamePasswordToken) token;
        String username=uptoken.getUsername();
        //调用YSysUserMapper中的方法查询用户的正确信息
        SysUsers user=sysUsersMapper.selectUserByName(username);
        if(user==null){
            throw  new UnknownAccountException("用户名不存在!");
        }
        if(user.getValid()==0){
            throw new LockedAccountException("该用户被禁用");
        }
        //将user对象中的salt有 String 转换为 ByteSource
        ByteSource credentialsSalt=ByteSource.Util.bytes(user.getSalt());

        //将正确的用户信息封装到AuthenticationInfo的 实现类对象中并返回
       SimpleAuthenticationInfo info= new SimpleAuthenticationInfo(
               user, //认证身份  用户对象 用户名
               user.getPassword(), //加密后的密码
               credentialsSalt, //盐值
               getName()  // getName()获取当前Realm名称即可
       );
        return info;
    }

    /**
     * 设置凭证匹配器  密码
     * @param credentialsMatcher
     */

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        //创建凭证匹配器对象
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(3);
        super.setCredentialsMatcher(matcher);
    }

}
